import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;


public class VendingMachineTest 
{

	VendingMachineItem itema;
	VendingMachine machinea;
	VendingMachine machineb;
	VendingMachine machinec;
	
	@Before
	public void setUp() throws Exception 
	{
		itema = new VendingMachineItem("A",1);
		machinea = new VendingMachine();
		machineb = new VendingMachine();
		machinec = new VendingMachine();
		
	}
	@Test(expected=VendingMachineException.class)
	public void testAddItem() 
	{
		//Testing precondition that the slot is empty.
		assertNull(machinea.getItem(VendingMachine.B_CODE));
		machinea.addItem(itema,VendingMachine.B_CODE);
		//Testing  postcondition to make sure item is added in the slot.
		assertEquals(itema, machinea.getItem(VendingMachine.B_CODE));
		//Testing exception case, if method throws exception when more item is added on the same slot.
		machinea.addItem(itema,VendingMachine.B_CODE);
	}

	@Test(expected=VendingMachineException.class)
	public void testRemoveItem() 
	{
		machinea.addItem(itema, VendingMachine.A_CODE);
		//Testing precondition that item must exist on the slot.
		assertEquals(itema, machinea.getItem(VendingMachine.A_CODE));
		machinea.removeItem(VendingMachine.A_CODE);
		//Testing if item is removed or not.
		assertNull(machinea.getItem(VendingMachine.A_CODE));
		//Exception testing if invalid code is provided.
		machinea.removeItem("INVALID_CODE");
		//Exception testing on the empty slot by trying to remove again.
		machinea.removeItem(VendingMachine.A_CODE);
	}

	@Test(expected=VendingMachineException.class)
	public void testInsertMoney() 
	{
		//Precondition check by exception through balance verification.
		machinea.insertMoney(-1.00);
		double previousBalance = machinea.getBalance();
		machinea.insertMoney(1.0);
		assertTrue(previousBalance + 1.0 -  machinea.getBalance() == 0);
	}

	@Test
	public void testGetBalance() 
	{
		//Testing beginning balance using Machine b.
		assertTrue(machineb.getBalance()==0);
		//Testing the post condition by getting the balance.
		assertTrue(machineb.getBalance()==0);
		double money = 1.75;
		//Testing by adding more money and getting the new balance.
		machineb.insertMoney(money);
		//verifying the new balance.
		assertTrue(machineb.getBalance()-money == 0);
		//Testing the post condition again to verify the correct balance.
		assertTrue(machineb.getBalance()-money == 0);
	}

	@Test
	public void testMakePurchase() 
	{
		//Testing the precondition by checking the available balance.
		assertTrue(machinea.getBalance() >=0);
		//Adding a item in the slot.
		machinea.addItem(new VendingMachineItem("Candy",0.75),VendingMachine.C_CODE);
		//Testing by adding money in the machine.
		machinea.insertMoney(1.5);
		assertTrue(machinea.getBalance()-1.5 == 0);
		//Testing if purchase can be made using the 
		assertTrue(machinea.makePurchase(VendingMachine.C_CODE));		
		//Testing the available balance again.
		assertTrue(machinea.getBalance()-0.75 == 0);
		
		//Testing for the null data.
		assertFalse(machinea.makePurchase(VendingMachine.C_CODE));		
		//Testing for a purchase with insufficient balance for the purchase.
		machinea.addItem(new VendingMachineItem("KingSizeCandy",3.00),VendingMachine.D_CODE);
		assertFalse(machinea.makePurchase(VendingMachine.D_CODE));
	}

	@Test
	public void testReturnChange() 
	{
		//Testing precondition if any balance is available already.
		assertTrue(machinec.getBalance() >=0);
		//Adding an item to the machine.
		machinec.addItem(new VendingMachineItem("Candy",0.75),VendingMachine.B_CODE);
		//Add $2 to machine.
		machinec.insertMoney(1.50);
		//Checking the balance of the money.
		assertTrue(machinec.getBalance() - 1.5 == 0);
		//Making the purchase of Candy for $0.75
		machinec.makePurchase(VendingMachine.B_CODE);
		// Checking the remainder after the purchase.
		assertTrue(machinec.getBalance() - 0.75 == 0);
		//Getting the change.
		assertTrue(machinec.returnChange() - 0.75 == 0);//change is 0.75
		//Testing the post condition that balance is zero after return is made.
		assertTrue(machinec.getBalance() == 0);
	}
}
